package com.gitee.gateway.core.db;

import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import jodd.bean.BeanUtil;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.sql.Blob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 数据库记录，封装了常用的数据库操作
 */
public abstract class ModalRowMapper<T> implements RowMapper<T> {

    private final static Map<String, Field> fieldTypes = new ConcurrentHashMap<>();

    /**
     * 自动转换 JsonObject 属性
     *
     * @param rs  ResultSet 对象
     * @param ctx StatementContext 对象
     * @return 从结果集中获取的对象
     * @throws SQLException SQL 异常
     */
    @Override
    @SuppressWarnings("unchecked")
    public T map(ResultSet rs, StatementContext ctx) throws SQLException {
        Map<String, Object> datas = new HashMap<>();
        ResultSetMetaData rsmd = rs.getMetaData();
        for (int i = rsmd.getColumnCount(); i > 0; i--) {
            String fieldName = rsmd.getColumnLabel(i);
            Field field = fieldTypes.computeIfAbsent(getClass().getName() + "." + fieldName, k -> FieldUtils.getField(getClass(), fieldName, true));
            if (field == null || Modifier.isStatic(field.getModifiers()))
                continue;
            Class<?> fieldType = field.getType();
            if (JsonObject.class.equals(fieldType)) {
                String json = rs.getString(fieldName);
                if (json != null && !"null".equals(json))
                    datas.put(fieldName, new JsonObject(json));
                continue;
            }
            if (JsonArray.class.equals(fieldType)) {
                String json = rs.getString(fieldName);
                if (json != null && !"null".equals(json))
                    datas.put(fieldName, new JsonArray(json));
                continue;
            }
            if (fieldType.isEnum()) {
                String value = rs.getString(fieldName);
                Object enumObj = null;
                try {
                    enumObj = fieldType.getMethod("valueOf", String.class).invoke(fieldType, value);
                    datas.put(fieldName, enumObj);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    throw new SQLException(e);
                }
                continue;
            }
            // 对象关联属性的处理方式
            if (Modal.class.isAssignableFrom(fieldType)) {
                try {
                    long value = rs.getLong(fieldName);
                    var modal = fieldType.getDeclaredConstructor().newInstance();
                    BeanUtil.pojo.setProperty(modal, "id", value);
                    //BeanUtils.setProperty(modal, "id", value);
                    datas.put(fieldName, modal);
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                         InstantiationException e) {
                    throw new SQLException(e);
                }
                continue;
            }
            //Blob 字段
            if (Blob.class.isAssignableFrom(fieldType)) {
                datas.put(fieldName, rs.getBlob(fieldName));
                continue;
            }
            Object obj = rs.getObject(fieldName);
            if (obj != null)
                datas.put(fieldName, obj);
        }
        try {
            var obj = this.getClass().getDeclaredConstructor().newInstance();
            datas.forEach((k, v) -> BeanUtil.pojo.setProperty(obj, k, v));
            return (T) obj;
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            throw new SQLException(e);
        }
    }

}
